<!DOCTYPE html>
<html>
    <head>
        <title>Test Encryption Scheme</title>
        <script src="encrypted-media-utils.js"></script>
        <script src="../../resources/testharness.js"></script>
        <script src="../../resources/testharnessreport.js"></script>
    </head>
    <body>
        <script>
            // Checks that calling navigator.requestMediaKeySystemAccess()
            // with |configuration| selects a configuration where the first
            // entry in audioCapabilities and videoCapabilities contains
            // encryptionScheme of |expectedAudioScheme| or
            // |expectedVideoScheme|, respectively. If |expectedAudioScheme| or
            // |expectedVideoScheme| is undefined, then no corresponding
            // capability should have been selected.
            function expectSupport(configuration, expectedAudioScheme, expectedVideoScheme, testName) {
                promise_test(async test => {
                    var access = await navigator.requestMediaKeySystemAccess('org.w3.clearkey', configuration);
                    var result = access.getConfiguration();
                    if (result.audioCapabilities.length > 0) {
                        assert_equals(result.audioCapabilities[0].encryptionScheme, expectedAudioScheme, 'audio scheme');
                    } else {
                        assert_equals(undefined, expectedAudioScheme, 'expected audio scheme missing');
                    }
                    if (result.videoCapabilities.length > 0) {
                        assert_equals(result.videoCapabilities[0].encryptionScheme, expectedVideoScheme, 'video scheme');
                    } else {
                        assert_equals(undefined, expectedVideoScheme, 'expected video scheme missing');
                    }
                }, testName);
            }

            // Verifies that calling navigator.requestMediaKeySystemAccess()
            // with |configuration| fails (due to no encryptionScheme being
            // supported).
            function expectFailure(configuration, testName) {
                promise_test(async test => {
                    try {
                        await navigator.requestMediaKeySystemAccess('org.w3.clearkey', configuration);
                        assert_unreached('Unexpected requestMediaKeySystemAccess() success.');
                    } catch(error) {
                        // Error is what we want to happen.
                    }
                }, testName);
            }

            // Creates an audioCapabilities sequence with one entry, including
            // |encryption_scheme| if specified.
            function getAudioCapabilities(encryptionScheme) {
                var capability = [{contentType: 'audio/webm; codecs="opus"'}];
                if (encryptionScheme !== undefined) {
                    capability[0].encryptionScheme = encryptionScheme;
                }
                return capability;
            }

            // Creates an videoCapabilities sequence with one entry, including
            // |encryption_scheme| if specified.
            function getVideoCapabilities(encryptionScheme) {
                var capability = [{contentType: 'video/webm; codecs="vp8"'}];
                if (encryptionScheme !== undefined) {
                    capability[0].encryptionScheme = encryptionScheme;
                }
                return capability;
            }

            // Takes a set of capabilities (passed as arguments) and combines
            // them into a MediaKeySystemConfiguration dictionary. If multiple
            // arguments define the same property, the last one overrides the
            // previous entry.
            function buildConfiguration() {
                var configuration = { initDataTypes : [ 'webm' ] };
                for (var i = 0; i < arguments.length; i++) {
                    for (var arg in arguments[i]) {
                        if (arg == 'audio') {
                            configuration['audioCapabilities'] =
                                getAudioCapabilities(arguments[i][arg]);
                        } else if (arg == 'video') {
                            configuration['videoCapabilities'] =
                                getVideoCapabilities(arguments[i][arg]);
                        }
                    }
                }
                return configuration;
            }

            // Test "cenc".
            expectSupport([buildConfiguration({audio: 'cenc'})],
                'cenc', undefined, 'Audio supports cenc');
            expectSupport([buildConfiguration({video: 'cenc'})],
                undefined, 'cenc', 'Video supports cenc');
            expectSupport([buildConfiguration({audio: 'cenc'}, {video: 'cenc'})],
                'cenc', 'cenc', 'Audio and Video supports cenc');

            // Test "cbcs".
            expectSupport([buildConfiguration({audio: 'cbcs'})],
                'cbcs', undefined, 'Audio supports cbcs');
            expectSupport([buildConfiguration({video: 'cbcs'})],
                undefined, 'cbcs', 'Video supports cbcs');
            expectSupport([buildConfiguration({audio: 'cbcs'}, {video: 'cbcs'})],
                'cbcs', 'cbcs', 'Audio and Video supports cbcs');

            // Test "cbcs-1-9".
            expectSupport([buildConfiguration({audio: 'cbcs-1-9'})],
                'cbcs-1-9', undefined, 'Audio supports cbcs-1-9');
            expectSupport([buildConfiguration({video: 'cbcs-1-9'})],
                undefined, 'cbcs-1-9', 'Video supports cbcs-1-9');
            expectSupport([buildConfiguration({audio: 'cbcs-1-9'}, {video: 'cbcs-1-9'})],
                'cbcs-1-9', 'cbcs-1-9', 'Audio and Video supports cbcs-1-9');

            // Test "invalid", which should fail.
            expectFailure([buildConfiguration({audio: 'invalid'})],
                'Audio fails with invalid scheme');
            expectFailure([buildConfiguration({video: 'invalid'})],
                'Video fails with invalid scheme');
            expectFailure([buildConfiguration({audio: 'invalid'}, {video: 'invalid'})],
                'Audio and Video fails with invalid scheme');
            expectFailure([buildConfiguration({audio: 'cenc'}, {video: 'invalid'})],
                'Audio valid, Video invalid scheme');
            expectFailure([buildConfiguration({audio: 'invalid'}, {video: 'cbcs'})],
                'Audio invalid scheme, Video valid with cbcs');
            expectFailure([buildConfiguration({audio: 'invalid'}, {video: 'cbcs-1-9'})],
                'Audio invalid scheme, Video valid with cbcs-1-9');

            // Test without encryptionScheme.
            expectSupport([buildConfiguration({audio: null})],
                null, undefined, 'Audio handles missing encryptionScheme');
            expectSupport([buildConfiguration({video: null})],
                undefined, null, 'Video handles missing encryptionScheme');
            expectSupport([buildConfiguration({audio: null}, {video: null})],
                null, null, 'Audio and Video handles missing encryptionScheme');
            expectSupport([buildConfiguration({audio: 'cbcs'}, {video: null})],
                'cbcs', null, 'Audio valid and Video missing');
            expectSupport([buildConfiguration({audio: null}, {video: 'cbcs'})],
                null, 'cbcs', 'Audio missing and Video valid');

            // Test with "", which is invalid.
            expectFailure([buildConfiguration({audio: ''})],
                'Audio handles empty encryptionScheme');
            expectFailure([buildConfiguration({video: ''})],
                'Video handles empty encryptionScheme');
            expectFailure([buildConfiguration({audio: ''}, {video: ''})],
                'Audio and Video handles empty encryptionScheme');
            expectFailure([buildConfiguration({audio: 'cbcs'}, {video: ''})],
                'Audio valid and Video empty');
            expectFailure([buildConfiguration({audio: ''}, {video: 'cbcs'})],
                'Audio empty and Video valid');

            // Test mixed combinations.
            expectSupport([buildConfiguration({audio: 'cenc'}, {video: 'cbcs'})],
                'cenc', 'cbcs', 'Audio supports cenc and Video supports cbcs');
            expectSupport([buildConfiguration({audio: 'cenc'}, {video: 'cbcs-1-9'})],
                'cenc', 'cbcs-1-9', 'Audio supports cenc and Video supports cbcs-1-9');
            expectSupport([buildConfiguration({audio: 'cbcs'}, {video: 'cenc'})],
                'cbcs', 'cenc', 'Audio supports cbcs and Video supports cenc');
            expectSupport([buildConfiguration({audio: 'cbcs'}, {video: 'cbcs-1-9'})],
                'cbcs', 'cbcs-1-9', 'Audio supports cbcs and Video supports cbcs-1-9');
            expectSupport([buildConfiguration({audio: 'cbcs-1-9'}, {video: 'cenc'})],
                'cbcs-1-9', 'cenc', 'Audio supports cbcs-1-9 and Video supports cenc');
            expectSupport([buildConfiguration({audio: 'cbcs-1-9'}, {video: 'cbcs'})],
                'cbcs-1-9', 'cbcs', 'Audio supports cbcs-1-9 and Video supports cbcs');

            // Test multiple configurations.
            expectSupport([buildConfiguration({audio: 'cenc'}),
                           buildConfiguration({audio: 'cbcs'})],
                'cenc', undefined, 'Multiple audio entries supports cenc');
            expectSupport([buildConfiguration({audio: 'cbcs'}),
                           buildConfiguration({audio: 'cenc'})],
                'cbcs', undefined, 'Multiple audio entries supports cbcs');
            expectSupport([buildConfiguration({video: 'cenc'}),
                           buildConfiguration({video: 'cbcs'})],
                undefined, 'cenc', 'Multiple video entries supports cenc');
            expectSupport([buildConfiguration({video: 'cbcs'}),
                           buildConfiguration({video: 'cenc'})],
                undefined, 'cbcs', 'Multiple video entries supports cbcs');

            // Test mixed multiple configurations.
            expectSupport([buildConfiguration({audio: 'cenc'}),
                           buildConfiguration({video: 'cbcs'})],
                'cenc', undefined, 'Mixed entries supports cenc');
            expectSupport([buildConfiguration({video: 'cbcs'}),
                           buildConfiguration({audio: 'cenc'})],
                undefined, 'cbcs', 'Mixed entries supports cbcs');

            // Test invalid values.
            expectFailure([buildConfiguration({audio: 3})],
                'Audio fails with numeric scheme');
            expectFailure([buildConfiguration({audio: [1, 2, 3]})],
                'Audio fails with array scheme');
            expectFailure([buildConfiguration({audio: {test: 'test'}})],
                'Audio fails with object scheme');
        </script>
    </body>
</html>
